package org.nativejpa.query;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.sql.Types;
import java.sql.Clob;
import java.sql.Timestamp;
import java.math.BigDecimal;
import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.util.Date;

/**
 * @author <a href="mailto:jfox.young@gmail.com">Young Yang</a>
 * @create 2009-3-18 17:16:43
 */
public class DefaultJDBCMapper extends JDBCMapper {

    public Object getResultSetObject(ResultSet rset, Class columnClass, int columnIndex) throws SQLException {
        Object value = null;
        if (Boolean.class == columnClass || boolean.class == columnClass) {
            value = rset.getBoolean(columnIndex);
        }
        else if (Byte.class == columnClass || byte.class == columnClass) {
            value = rset.getByte(columnIndex);
        }
        else if (Character.class.equals(columnClass) || char.class.equals(columnClass)) { // 使用 Byte 设置 Char
            value = rset.getString(columnIndex).charAt(0);
        }
        else if (Short.class == columnClass || short.class == columnClass) {
            value = rset.getShort(columnIndex);
        }
        else if (Integer.class == columnClass || int.class == columnClass) {
            value = rset.getInt(columnIndex);
        }
        else if (Long.class == columnClass || long.class == columnClass) {
            value = rset.getLong(columnIndex);
        }
        else if (Float.class == columnClass || float.class == columnClass) {
            value = rset.getFloat(columnIndex);
        }
        else if (Double.class == columnClass || double.class == columnClass) {
            value = rset.getDouble(columnIndex);
        }
        else if (BigDecimal.class == columnClass) {
            value = rset.getBigDecimal(columnIndex);
        }
        else if (byte[].class == columnClass) {
            try {
                InputStream in = rset.getBinaryStream(columnIndex);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int n;
                byte[] buffer = new byte[1024];
                while ((n = in.read(buffer)) != -1) {
                    baos.write(buffer, 0, n);
                }
                value = baos.toByteArray();
                in.close();
            }
            catch (IOException e) {
                value = rset.getBytes(columnIndex);
            }
        }
        else if (java.lang.String.class == columnClass) {
            //deal with CLOB, 使用 rset.getCharactorStream 统一处理
/*
            try {
                Reader reader = rset.getCharacterStream(columnIndex);
                StringWriter sw = new StringWriter();

                int n;
                char[] buffer = new char[1024];
                while (-1 != (n = reader.read(buffer))) {
                    sw.write(buffer, 0, n);
                }
                value = sw.toString();
            }
            catch(IOException e) {
                value = rset.getString(columnIndex);
            }
*/

            if (rset.getMetaData().getColumnType(columnIndex) == Types.CLOB) {
                Clob clob = rset.getClob(columnIndex);
                if (clob != null) {
                    value = clob.getSubString(1, (int) clob.length());
                }
            }
            else {
                value = rset.getString(columnIndex);
            }

        }
        else if (Date.class == columnClass) {
            java.sql.Date sqldate = rset.getDate(columnIndex);
            if (sqldate != null) {
                value = new Date(sqldate.getTime());
            }
        }
        else if (java.sql.Date.class == columnClass) {
            value = rset.getDate(columnIndex);
        }
        else if (Timestamp.class == columnClass) {
            value = rset.getTimestamp(columnIndex);
        }
        else {
            value = rset.getObject(columnIndex);
        }
        return value;

    }

    public void setPreparedStatementObject(PreparedStatement pst, int index, Object value) throws SQLException {
        if (value == null) {
            pst.setObject(index, null);
//            pst.setNull(index, pst.getParameterMetaData().getParameterType(index));
            return;
        }
        Class<?> clazz = value.getClass();

        if (Boolean.class.equals(clazz) || boolean.class.equals(clazz)) {
            pst.setBoolean(index, (Boolean) value);
        }
        else if (Byte.class.equals(clazz) || byte.class.equals(clazz)) {
            pst.setByte(index, (Byte) value);
        }
        else if (Character.class.equals(clazz) || char.class.equals(clazz)) { // 使用 Byte 设置 Char
            pst.setString(index, (((Character) value).charValue()) + "");
        }
        else if (Short.class.equals(clazz) || short.class.equals(clazz)) {
            pst.setShort(index, (Short) value);
        }
        else if (Integer.class.equals(clazz) || int.class.equals(clazz)) {
            pst.setInt(index, (Integer) value);
        }
        else if (Long.class.equals(clazz) || long.class.equals(clazz)) {
            pst.setLong(index, (Long) value);
        }
        else if (Float.class.equals(clazz) || float.class.equals(clazz)) {
            pst.setFloat(index, (Float) value);
        }
        else if (Double.class.equals(clazz) || double.class.equals(clazz)) {
            pst.setDouble(index, (Double) value);
        }
        else if (BigDecimal.class.equals(clazz)) {
            pst.setBigDecimal(index, ((java.math.BigDecimal) value));
        }
        else if (String.class.equals(clazz)) {
            pst.setString(index, ((String) value));
        }
        else if (Date.class.equals(clazz)) {
            pst.setDate(index, new java.sql.Date(((Date) value).getTime()));
        }
        else if (java.sql.Date.class.equals(clazz)) {
            pst.setDate(index, (java.sql.Date) value);
        }
        else if (Timestamp.class.equals(clazz)) {
            pst.setTimestamp(index, (Timestamp) value);
        }
        else if(byte[].class.equals(clazz)) { // blob
            pst.setBinaryStream(index, new ByteArrayInputStream((byte[])value), ((byte[])value).length);
        }
        else {
            pst.setObject(index, value);
        }
    }
}
